# 策略模板
# write by hashaki first edit on 200181019 last fix on 2018/11/24
# build in python3.5

"""
陈卓杰日志
在策略实例创建的时候，加入参数字典setting
"""

from hashakisea.constant.chinese import (DIRECTION_LONG,OFFSET_OPEN,CTAORDER_BUY,CTAORDER_SELL,
        OFFSET_CLOSE,CTAORDER_SHORT,CTAORDER_COVER,DIRECTION_SHORT)
from hashakisea.constant.objectClass import OtherIndexClass
from datetime import datetime

################################################################################
class SrategyTamplate:
    """策略模板"""
    # -------------------------------------------------------------------------
    def __init__(self,backtestingEnging, setting):
        """构造器"""
        # 策略基本信息
        self.className = "CtaTemplate"      # 策略类名称
        self.strategy_name = "strategy"     # 策略名称
        self.author = ""                    # 策略作者
        self.symbol = ""                    # 策略代码,"Binance.BTC_USDT"
        self.frequency = ""                 # 策略推送K线的频率
        self.other_bar=None                 # OtherIndexClass()
        # 策略基本变量, 由引擎管理
        self.inited = False                 # 是否进行了初始化
        self.trading = True                # 是否启动交易，由引擎管理

        # 引擎实例
        self.backtestingEnging = backtestingEnging

        # 参数列表, 传入的setting进行赋值
        self.paramList = ["className","strategy_name",
                          "author", "symbol", "frequency"]

        # 设置策略的参数
        if setting:
            d = self.__dict__
            for key in self.paramList:
                if key in setting:
                    d[key] = setting[key]

        # 保存委托单编号和相关委托单的字典
        # key为委托单编号
        # value为该合约相关的委托单
        self.uncompletedOrders = {}

    # --------------------------------------------------------------
    #策略开发部分
    def start(self):
        """有关策略的初始化设置"""
        raise NotImplementedError

    def next(self, bar):
        """每一根K线调用一次"""
        raise NotImplementedError

    def onOrder(self, order):
        """每一次发单都调用一次"""
        raise NotImplementedError

    def onTrade(self,trade):
        """每一次交易都调用一次"""
        raise NotImplementedError

    # --------------------------------------------------------------
    # --------------------------------------------------------------
    # 策略模板内部函数
    # 代表broker的功能
    def buy(self, target_symbol,price, volume, stop=False ,orderTime=None, grid=None):
        '''买,传回broker'''
        if orderTime is None:
            orderTime = datetime.now()

        orderID = self.sendOrder(target_symbol,CTAORDER_BUY,price, volume, stop)
        if orderID !='':
            self.entrust = 1                            # 委托状态
            d = {'DIRECTION': DIRECTION_LONG, 'OFFSET': OFFSET_OPEN,
                 'Volume': volume, 'TradedVolume': 0,
                 'Price': price, 'OrderTime': orderTime}
            if grid is not None:
                d['Grid'] = grid

            self.uncompletedOrders[orderID] = d
            return orderID
        else:
            # 交易停止时发单返回空字符串
            return ''

    def sell(self, target_symbol,price, volume, stop=False, orderTime=None, grid=None):
        '''卖，传回broker'''
        if orderTime is None:
            orderTime = datetime.now()

        orderID = self.sendOrder(target_symbol,CTAORDER_SELL, price, volume, stop)
        if orderID !='':
            self.entrust = -1                           # 置当前策略的委托单状态
            # 记录委托单
            d = {'DIRECTION': DIRECTION_SHORT,'OFFSET': OFFSET_CLOSE,
                 'Volume': volume, 'TradedVolume': 0,
                 'Price': price, 'OrderTime': orderTime}
            if grid is not None:
                d['Grid'] = grid
            self.uncompletedOrders[orderID] = d
            return orderID
        else:
            # 交易停止时发单返回空字符串
            return ''
    
    def cancel(self,target_symbol,orderID=None):
        '''取消订单'''
        self.backtestingEnging.broker.cancel(target_symbol,orderID)
    
    def short(self,target_symbol, price, volume, stop=False, orderTime=None, grid = None):
        """卖开"""
        if orderTime is None:
            orderTime = datetime.now()

        orderID = self.sendOrder(target_symbol,CTAORDER_SHORT, price, volume, stop)
        if orderID !='':
            self.entrust = -1                           # 委托状态
            d = {'DIRECTION': DIRECTION_SHORT, 'OFFSET': OFFSET_OPEN,
                 'Volume': volume, 'TradedVolume': 0,
                 'Price': price, 'OrderTime':  orderTime }
            if grid is not None:
                d['Grid'] = grid
            self.uncompletedOrders[orderID] = d
            return orderID
        else:
            # 交易停止时发单返回空字符串
            return ''
    
    def cover(self, target_symbol,price, volume, stop=False, orderTime=None, grid = None):
        """买平"""
        if orderTime is None:
            orderTime = datetime.now()

        orderID = self.sendOrder(target_symbol,CTAORDER_COVER, price, volume, stop)

        if orderID !='':
            self.entrust = 1                           # 置当前策略的委托单状态
            # 记录委托单
            d ={'DIRECTION': DIRECTION_LONG, 'OFFSET': OFFSET_CLOSE,
                 'Volume': volume, 'TradedVolume': 0,
                 'Price': price, 'OrderTime': orderTime}
            if grid is not None:
                d['Grid'] = grid
            self.uncompletedOrders[orderID] = d
            return orderID
        else:
            # 交易停止时发单返回空字符串
            return ''
    
    def sendOrder(self, target_symbol,orderType, price, volume, stop=False):
        """发送委托"""
        if self.trading:
            # 如果stop为True，则意味着发本地停止单
            if stop:
                HaOrderID = self.backtestingEnging.sendStopOrder(target_symbol, orderType, price, volume, self.strategy_name)
            else:
                HaOrderID = self.backtestingEnging.sendOrder(target_symbol,orderType, price, volume, self.strategy_name)
            return HaOrderID
        else:
            # 交易停止时发单返回空字符串
            return ''

    def getHistoryData(self, symbol, frequency, num=20):
        """获取指定品种,周期的前num根K线"""
        # TODO：读取加进引擎的其他周期K线
        tamp_name=symbol+'_'+frequency
        count_bar=self.backtestingEnging.calculateBarCMP(tamp_name)
        tamp_data=self.backtestingEnging.kwargs[tamp_name][count_bar-num:count_bar+1]   # 获取该品种周期的数据，[(),(),...]
        self.other_bar.target_symbol=symbol
        self.other_bar.frequence=frequency
        return tamp_data

    @property
    def indicator(self):
        """指标计算器"""
        return self.backtestingEnging.indicator

    @property
    def pos(self):
        """最新的持仓"""
        return self.backtestingEnging.pos

    @property
    def posList(self):
        """持仓序列"""
        return self.backtestingEnging.posList

    @property
    def marketValueList(self):
        """市值序列"""
        return self.backtestingEnging.marketValueList

    @property
    def cashList(self):
        """现金序列"""
        return self.backtestingEnging.cashList

    @property
    def depositList(self):
        """保证金序列"""
        return self.backtestingEnging.depositList

    @property
    def capitalList(self):
        """总资产序列"""
        return self.backtestingEnging.capitalList
